#!/usr/bin/python
# -*- coding: utf-8 -*-

import os, sys, threading, subprocess, copy, re, unicodedata, Queue, imghdr, signal, getopt
from time import sleep
from shutil import move, copy

# global directory variables 
thek = ""
db = ""
dir_img = ""
dir_sub = ""
dir_trs = ""
movies_path = ""

files = []
other_files = []

accepted_format = ["avi", "part", "m2ts", "mkv", "mp4", "divx"]
sub_format = ["srt"]

module_website = "IMDb"
number_records = 0

threadLock = threading.Lock()
threadLimit = threading.BoundedSemaphore(20)

force_reconstruction = False

class thread_info_file(threading.Thread):
	def __init__(self, file_to_check):
		threading.Thread.__init__(self)
		self.file_to_check = file_to_check
		self.potentials_records = None
		self.message = ""
		
	def run(self):
		threadLimit.acquire()
		self.get_info()
		threadLimit.release()
		print self.message + "\n"
		
	def parse_filename(self, filename, parser):
		self.potentials_records = []
		
		splits = filename.split(parser)
		if len(splits) == 1:
			splits = filename.split(".")
			if len(splits) == 1:
				splits = filename.split("-")
				
		#print splits
		
		find = False
		
		name_check = ""
		v = 0
		for split in splits:
			if not split or split in parser:
				continue
			
			name_check += split + " "
			
			# If there is at least 2 words
			if len(splits) > 1:
				# Allow only starting from the second split (name_check will contain 2 words)
				if v == 0:
					v += 1
					continue
			
			command = "gcstar -x -c GCfilms -w " + module_website + " --download " + "\"" + name_check + "\""
			self.message +=	"---- Command : " + command + "\n"
					
			process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
			
			recording = False
			record = ""
			
			# Title of the current item
			title = ""
						
			# read the current output line to record its features (xml)
			for line in iter(process.stdout.readline, ''):
				# Copy image
				if "<item" in line:
					n = -1
					recording = True
					record += line
				elif "</item>" in line:
					recording = False
					record += line
					
					if n != -1:
						self.potentials_records[n][2] = record
					else:
						print self.potentials_records
					# Check if the filename match with title
					find = self.check_name(filename, title)
					if find:
						self.copy_image(image_line)
						process.wait()
						return n
						
					record = ""
				elif recording:
					record += line
					# Manage title
					if "  title=\"" in line:
						pos = line.find("  title=\"", 0)
						title = line.split("title=\"").pop()
						title = title[:len(title) - 2]
						
						y = -1
						for prec in self.potentials_records:							
							if title.lower() in prec[0].lower():
								y += 1
								n = y
								prec[1] += 1
								break
								
						if y == -1:
							n = len(self.potentials_records)
							self.potentials_records.append([title, 1, ""])
					elif "  image=\"" in line:
						image_line = line
			
			process.wait()
			exit_code = process.returncode
		
		return -1
	
	def copy_image(self, text):
		obj_match = re.match("^.*image=\"(.+?)\".*$", text.replace("\n",""))
		
		#threadLock.acquire()
		if obj_match:
			image = obj_match.group(1)
			try:
				copy(image, dir_img)
				self.message += "Copy " + image + " to " + dir_img + "\n"
			except Exception, err:
				self.message += "- Impossible to find \"" + image + "\" (" + str(err) + ")\n" 
		#threadLock.release()
		
	def potentials_record(self, title):
		i = 0
		for prec in self.potentials_records:
			if title.lower() in prec[0].lower():
				return (i, prec)
			i += 1
		return None

	def check_name(self, src_name, dst_name):
		split_src = src_name.split(" ")
		split_dst = dst_name.split(" ")
		
		cnt = 0
		max_cnt = 0
		
		for word_dst in split_dst:
			match = re.match("^.*[0-9].*$", word_dst)
			
			# If contains a number
			if match:
				max_cnt += 1
			else:
				# If is superior or egal at 3
				if len(word_dst) >= 3:
					max_cnt += 1
		
		for word_dst in split_dst:
			for word_src in split_src:
				# Replace unicode characters to ascii characters
				cmp_dst = unicodedata.normalize('NFKD', unicode(word_dst, 'utf-8')).encode('ascii','ignore')
				cmp_src = unicodedata.normalize('NFKD', unicode(word_src, 'utf-8')).encode('ascii','ignore')
				
				# Remove special characters
				cmp_dst = re.sub(r"\W", r"", cmp_dst)
				cmp_src = re.sub(r"\W", r"", cmp_src)
				
				if cmp_src.lower() == cmp_dst.lower():
					cnt += 1
		
		if cnt >= max_cnt:
			return True
		else:
			return False

	def organize_dir(self, filename, id_record):
		# IMAGE
		obj_match = re.match("^.+image=\"(.*?)\".+$", self.potentials_records[id_record][2].replace("\n",""))
		
		image = None
		if obj_match:
			image = obj_match.group(1)
			if image:
				self.potentials_records[id_record][2] = self.potentials_records[id_record][2].replace("image=\"" + image + "\"",  "image=\"" + dir_img + "/" + image.split("/").pop() + "\"")
						
		# GENRE
		obj_match = re.match("^.+genre=\"(.+?)\".+$", self.potentials_records[id_record][2].replace("\n",""))
		
		genre = None
		if obj_match:
			genre = obj_match.group(1)
		else:
			return
		
		# Path where will use to move the file
		genre_dir = thek
		for g in genre.split(","):
			genre_dir += "/" + g
			if not os.path.exists(genre_dir):
				try:
					os.makedirs(genre_dir)
				except:
					pass
			# Just sort by first genre
			break
		
		try:
			move(filename, genre_dir)
		except:
			self.message += "- Can't move \"" + filename + "\" to \"" + genre_dir + "\"\n"
		
		self.potentials_records[id_record][2] = self.potentials_records[id_record][2].replace("trailer=\"\"",  "trailer=\"" + genre_dir + "/" + filename.split("/").pop() + "\"")
	
	def write_xml(self, id_record):
		threadLock.acquire()
		db_file = open(db, "a")
		db_file.write(self.potentials_records[id_record][2])
		db_file.close()
		threadLock.release()
				
	def get_info(self):
		filename = get_filename(self.file_to_check)
		self.message += "-------- Getting informations about \"" + filename + "\"\n"
		
		# Parse with space
		id_record = self.parse_filename(filename, " ")
		display = "- Not found \"" + filename + "\""
		
		if id_record != -1:
			display = "--- Find \"" + self.potentials_records[id_record][0] + "\""
		else:
			# Save found element to records
			i = 0
			max_count = -1
			for prec in self.potentials_records:
				self.message += "--\t Find potential \"" + prec[0] + "\" with " + str(prec[1]) + " occurrences\n"
				if prec[1] > max_count:
					max_count = prec[1]
					id_record = i
				i += 1
			
			if id_record != -1:
				display = "--- Select potential : \"" + self.potentials_records[id_record][0] + "\" (" + str(self.potentials_records[id_record][1]) + " occurrences)"
		
		self.message += display + "\n"
		
		if id_record != -1:
			self.write_xml(id_record)
			# Tidy up the file
			self.organize_dir(self.file_to_check, id_record)
			global number_records
			number_records += 1
	
def get_filename(file_to_check):
	filename_full = file_to_check.split("/").pop()
	# Get file name without extension
	extension = filename_full.split(".").pop()
	return filename_full.replace("." + extension, "")

def clean_other_files():
	for other_file in other_files:
		try:
			if os.path.splitext(other_file) in sub_format:
				move(other_file, dir_sub)
			elif imghdr.what(other_file):
				move(other_file, dir_img)
			else:
				move(other_file, dir_trs)
		except:
			pass

def create_xml():
	print "\t------ Generating item xml..."
	
	db_file = open(db, "r+")
	collection_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
	collection_xml += "<collection type=\"GCfilms\" items=\"" + str(number_records) +"\" version=\"1.6.2\">\n"
	collection_xml += "<information><maxId>" + str(number_records + 1) + "</maxId></information>\n\n"
	data = db_file.read()
	db_file.seek(0)
	db_file.write(collection_xml + data)
	db_file.close()
	
	db_file = open(db, "a")
	collection_xml = "</collection>"
	db_file.write(collection_xml)
	db_file.close()
	
def create_db():
	threads = []
	
	for file_to_check in files:
		thread = thread_info_file(file_to_check)
		thread.start()
		threads.append(thread)
			
	for thread in threads:
		thread.join()

def load_files():
	""" Move files if --force mode is actived """
	if force_reconstruction:
		for dirname, dirnames, filenames in os.walk(movies_path):
			for filename in filenames:
				if not os.path.exists(os.path.join(movies_path, filename)):
					if filename != db:
						move(os.path.join(dirname, filename), movies_path)
					
	""" Then add them to list """
	for s in os.listdir(movies_path):
		if os.path.isfile(os.path.join(movies_path, s)):
			if s.split(".").pop().lower() in accepted_format:
				files.append(os.path.join(movies_path, s))
			else:
				other_files.append(os.path.join(movies_path, s))
	
def init():
	# Load global directory variables
	global thek, db, dir_trs, dir_img, dir_sub
	thek = os.path.join(movies_path, "Movies")
	db = os.path.join(thek, "db.gcs")
	dir_trs = os.path.join(thek, "Trash")
	dir_img = os.path.join(thek, "Images")
	dir_sub = os.path.join(thek, "Subtitles")
	
	try:
		os.makedirs(thek)
	except:
		pass
	
	try:
		os.makedirs(dir_img)
	except:
		pass
		
	try:
		os.makedirs(dir_sub)
	except:
		pass	
		
	try:
		os.makedirs(dir_trs)
	except:
		pass
	
	# Create file
	if force_reconstruction or not os.path.exists(db):
		db_file = open(db, "w+")
		db_file.close()
	
	# Procedures
	load_files()
	clean_other_files()
	create_db()
	create_xml()


def usage():
	out = "---- Usage: python managethek.py -d PATH\n\
\t Managethek will create a GCStar XML to your videothek, get content on the web\n\
\t and also reorganize your directory\n\
-- Options:\n\
\t-d, --directory \t\t Directory path to your videothek \n\
\t-n, --new       \t\t Create new project\n\
\t-h, --help      \t\t Print this message\n\
"
	print out

if __name__ == "__main__":
	try:
		opts, args = getopt.getopt(sys.argv[1:], "d:nh", ["directory=", "new", "help"])
	except getopt.GetoptError, err:
		print str(err) 
		sys.exit(2)
	
	if not opts:
		usage()
		sys.exit()
	
	for opt, arg in opts:
		if opt in ("-d", "--directory"):
			if os.path.exists(arg):
				movies_path = os.path.abspath(arg)
			else:
				print "Error \"" + arg + "\" doesn't exist" 
				sys.exit(2)
		elif opt in ("-n", "--new"):
			force_reconstruction = True
		elif opt in ("-h", "--help"):
			usage()
			sys.exit()
			
	init()
